/*
 * Copyright (c) 2009 Roman Savelyev
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <e32uid.h>
#include "ReceiveE32ImageHeader.h"
#include "AppHookModel.h"
#include "HostLink.h"
#include "Sandbox.h"
#include "Log.h"

static const TUint32 KEPOCSignature = 0x434f5045;
static const TUint32 KNoCompression = 0;

CReceiveE32ImageHeader* CReceiveE32ImageHeader::NewL(CAppHookModel& aModel)
    {
    LOG(_L("-->CReceiveE32ImageHeader::NewL"));
    CReceiveE32ImageHeader* self = new(ELeave) CReceiveE32ImageHeader(aModel);
    self->Construct();
    LOG(_L("<--CReceiveE32ImageHeader::NewL"));
    return self;
    }

CReceiveE32ImageHeader::~CReceiveE32ImageHeader()
    {
    LOG(_L("-->CReceiveE32ImageHeader::~CReceiveE32ImageHeader"));
    Cancel();
    LOG(_L("<--CReceiveE32ImageHeader::~CReceiveE32ImageHeader"));
    }

CReceiveE32ImageHeader::CReceiveE32ImageHeader(CAppHookModel& aModel) : CActive(CActive::EPriorityStandard),
    iModel(aModel),
    iReadBuffer((TUint8*)&iHeader, sizeof(iHeader))
    {
    CActiveScheduler::Add(this);
    }

void CReceiveE32ImageHeader::Construct()
    {
    LOG(_L("-->CReceiveE32ImageHeader::Construct"));
    iState = ERecognizeEPOC;
    iStatus = KRequestPending;
    // Read uid1, uid2, uid3, uidcrc and signature
    iReadBuffer.Set((TUint8*)&iHeader, 0, _FOFF(E32ImageHeaderV, iHeaderCrc));
    iModel.HostLink().ReadHost(iReadBuffer, iStatus);
    SetActive();
    LOG(_L("<--CReceiveE32ImageHeader::Construct"));
    }

void CReceiveE32ImageHeader::RunL()
    {
    TInt error = iStatus.Int();
    LOG2(_L("-->CReceiveE32ImageHeader::RunL(%d)"), error);
    if (KErrNone == error)
        {
        switch (iState)
            {
            case ERecognizeEPOC:
                {
                HandleRecognizeEPOCL();
                }
                break;
            case ECheckCompression:
                {
                HandleCheckCompressionL();
                }
                break;
            case EReadHeader:
                {
                HandleReadHeaderL();
                }
                break;
            default:
                {
                User::Invariant();
                }
            }
        }
    else if (KErrCancel != error)
        {
        User::Leave(error);
        }
    }

void CReceiveE32ImageHeader::DoCancel()
    {
    iModel.HostLink().CancelReadHost();
    }

TInt CReceiveE32ImageHeader::RunError(TInt aError)
    {
    LOG2(_L("-->CReceiveE32ImageHeader::RunError(%d)"), aError);
    iModel.ReceiveE32ImageHeaderComplete(aError);
    LOG(_L("<--CReceiveE32ImageHeader::RunError"));
    return KErrNone;
    }

void CReceiveE32ImageHeader::HandleRecognizeEPOCL()
    {
    LOG(_L("-->CReceiveE32ImageHeader::HandleRecognizeEPOCL"));
    __ASSERT_ALWAYS(iHeader.iSignature == KEPOCSignature, User::Leave(KErrCorrupt));
    __ASSERT_ALWAYS(iHeader.iUid1 == KExecutableImageUidValue, User::Leave(KErrNotSupported));
    iState = ECheckCompression;
    iStatus = KRequestPending;
    TUint8* headerPtr = (TUint8*)&iHeader;
    iReadBuffer.Set(headerPtr + _FOFF(E32ImageHeaderV, iHeaderCrc), 0, _FOFF(E32ImageHeaderV, iToolsVersion));
    iModel.HostLink().ReadHost(iReadBuffer, iStatus);
    SetActive();
    LOG(_L("<--CReceiveE32ImageHeader::HandleRecognizeEPOCL"));
    }

void CReceiveE32ImageHeader::HandleCheckCompressionL()
    {
    LOG(_L("-->CReceiveE32ImageHeader::HandleCheckCompressionL"));
    __ASSERT_ALWAYS(iHeader.iCompressionType == KNoCompression, User::Leave(KErrNotSupported));
    iState = EReadHeader;
    iStatus = KRequestPending;
    TUint8* headerPtr = (TUint8*)&iHeader;
    iReadBuffer.Set(headerPtr + _FOFF(E32ImageHeaderV, iToolsVersion), 0, sizeof(E32ImageHeaderV) - _FOFF(E32ImageHeaderV, iToolsVersion));
    iReadBuffer.Zero();
    iModel.HostLink().ReadHost(iReadBuffer, iStatus);
    LOG(_L("<--CReceiveE32ImageHeader::HandleCheckCompressionL"));
    }

void CReceiveE32ImageHeader::HandleReadHeaderL()
    {
    LOG(_L("-->CReceiveE32ImageHeader::HandleReadHeaderL"));
    TUint32 dummyUncompressedSize;
    //User::LeaveIfError(iHeader.ValidateHeader(iModel.Sandbox().ImageSize(), dummyUncompressedSize));
    iModel.Sandbox().ProcessE32ImageHeaderL(iHeader);
    LOG(_L("<--CReceiveE32ImageHeader::HandleReadHeaderL"));
    }
